<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="P0DcZ" id="P0DcZ"><span data-lake-id="u9fb20a92" id="u9fb20a92">典型回答</span></h1>
  <p data-lake-id="uec23b1a8" id="uec23b1a8"><br></p>
  <p data-lake-id="ue6f64ac7" id="ue6f64ac7"><span data-lake-id="u83f591c3" id="u83f591c3">随着业务量的增长，为了提升整体系统的可用性、性能及可扩展性，很多大型互联网公司都会采用微服务架构，一次业务请求，一般要经过几个微服务调用才能完成，。</span></p>
  <p data-lake-id="u712c6411" id="u712c6411"><span data-lake-id="uc6df1c45" id="uc6df1c45">​</span><br></p>
  <p data-lake-id="ue3e6ecdf" id="ue3e6ecdf"><span data-lake-id="ue0ef4918" id="ue0ef4918">一次请求之间要经过很多的系统，那么如何追踪一次请求从头到尾的流程，就至关重要，这样可以帮我们做很好的链路分析，及问题定位。</span></p>
  <p data-lake-id="ubdbf0033" id="ubdbf0033"><span data-lake-id="u5d48c720" id="u5d48c720">​</span><br></p>
  <p data-lake-id="ub6704700" id="ub6704700"><span data-lake-id="u7aa9da2e" id="u7aa9da2e">在业内，有很多链路追踪的工具，如Google的dapper、twitter的zipkin、京东的hydra、大众点评的cat，以及开源的skywalking。建议大家看看Google的这篇论文，可以说它是分布式链路追踪的启蒙之作：</span><a href="https://bigbully.github.io/Dapper-translation/" target="_blank" data-lake-id="ub8053fc2" id="ub8053fc2"><span data-lake-id="u8824056a" id="u8824056a">https://bigbully.github.io/Dapper-translation/</span></a><span data-lake-id="ue0013739" id="ue0013739"> </span></p>
  <p data-lake-id="u972daca5" id="u972daca5"><span data-lake-id="u6255d10a" id="u6255d10a">​</span><br></p>
  <p data-lake-id="u6acdf3b7" id="u6acdf3b7"><span data-lake-id="u9a38932a" id="u9a38932a">不管是哪个实现，在我看来重点就是解决两个问题：</span></p>
  <p data-lake-id="ufd9d9d03" id="ufd9d9d03"><span data-lake-id="ube94f77a" id="ube94f77a">​</span><br></p>
  <p data-lake-id="u5ff76bef" id="u5ff76bef"><span data-lake-id="u0646f84d" id="u0646f84d">1、生成一个全局的traceId</span></p>
  <p data-lake-id="u2d74dbfe" id="u2d74dbfe"><span data-lake-id="u55806dce" id="u55806dce">2、把这个traceId传递下去</span></p>
  <p data-lake-id="u41f1f777" id="u41f1f777"><span data-lake-id="u3ea03b66" id="u3ea03b66">​</span><br></p>
  <h3 data-lake-id="NtfmW" id="NtfmW"><span data-lake-id="ua3ef31fb" id="ua3ef31fb">生成TraceId</span></h3>
  <p data-lake-id="ub705d2fd" id="ub705d2fd"><span data-lake-id="udb9ad74f" id="udb9ad74f">​</span><br></p>
  <p data-lake-id="u9157b952" id="u9157b952"><span data-lake-id="u807003d6" id="u807003d6">想要追踪一个完成的链路，就需要有一个标识来标记这次调用链，业内把他叫做traceId，一般会在入口处生成一个全局唯一的traceId，比如说在HTTP的请求入口，在定时任务的调度入口等，生成一个traceId。</span></p>
  <p data-lake-id="u78c43398" id="u78c43398"><br></p>
  <h3 data-lake-id="WXAtY" id="WXAtY"><span data-lake-id="u054183cf" id="u054183cf">传递TraceId</span></h3>
  <p data-lake-id="u32a5c11d" id="u32a5c11d"><br></p>
  <p data-lake-id="uc0063402" id="uc0063402"><span data-lake-id="u304425c6" id="u304425c6">在有了一个traceId之后，想要通过它把一次调用过程串联起来，那么就需要所有的系统间调用都得把他传递下去，这里面的调用包括了HTTP请求、RPC请求、MQ消息等，甚至还需要涉及到Redis、MySQL等等可能都需要进行传递。</span></p>
  <p data-lake-id="uba730377" id="uba730377"><span data-lake-id="uc0030b85" id="uc0030b85">​</span><br></p>
  <p data-lake-id="ue6cb656f" id="ue6cb656f"><span data-lake-id="u34eae4c7" id="u34eae4c7">所以，想要实现一个链路追踪，需要很多中间件一起配合才行，通常这个traceId会存放在RPC的请求头、HTTP的请求头、MQ消息的消息头中进行传递。</span></p>
  <p data-lake-id="udcc9ea7a" id="udcc9ea7a"><span data-lake-id="u24bc9db3" id="u24bc9db3">​</span><br></p>
  <p data-lake-id="u59a9382b" id="u59a9382b"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1686923696759-e759169b-56cf-4426-9478-ea72033988e1.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_20%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u5bad76c6" id="u5bad76c6"><span data-lake-id="u93ed968e" id="u93ed968e">​</span><br></p>
  <p data-lake-id="u0325ef69" id="u0325ef69"><span data-lake-id="u27e7411a" id="u27e7411a">系统之间通过这种方式，那系统内部也是需要传递的，所以一般都是用ThreadLocal来实现的，在接收到请求后，会把这个traceId存储在ThreadLocal中，然后就能在当前线程中一直传递下去，并且在记录日志的时候取出来打印到日志中，在需要调远程的时候，取出来传递下去。</span></p>
  <p data-lake-id="ub1565d18" id="ub1565d18"><span data-lake-id="uc672733e" id="uc672733e">​</span><br></p>
  <p data-lake-id="u4913475e" id="u4913475e"><span data-lake-id="u2b068a4e" id="u2b068a4e">但是，如果有多线程怎么办呢？ThreadLocal咋传递呢，这就要用到TTL了：</span></p>
  <p data-lake-id="uc17a58fe" id="uc17a58fe"><span data-lake-id="uc88b644f" id="uc88b644f">​</span><br></p>
  <p data-lake-id="u9ef40bde" id="u9ef40bde"><br></p>
  <h1 data-lake-id="opXEe" id="opXEe"><span data-lake-id="u2905f04d" id="u2905f04d">扩展知识</span></h1>
  <p data-lake-id="u0e05cf27" id="u0e05cf27"><br></p>
  <h2 data-lake-id="r2EmW" id="r2EmW"><span data-lake-id="u03a7b715" id="u03a7b715">Span</span></h2>
  <p data-lake-id="u3af3c376" id="u3af3c376"><br></p>
  <p data-lake-id="u0d0b143b" id="u0d0b143b"><span data-lake-id="uf1ed9989" id="uf1ed9989">前面提到了traceId，其实光有traceId还不够，trace帮我们把一次调用串联起来，但是一次调用在每一个系统上都干了什么，干了多久，成功还是失败，这些对我们来说也很重要，这些信息就被记录在span中。</span></p>
  <p data-lake-id="uad34f4df" id="uad34f4df"><span data-lake-id="u3b82bac9" id="u3b82bac9">​</span><br></p>
  <p data-lake-id="u854337e1" id="u854337e1"><span data-lake-id="ud9cfef4b" id="ud9cfef4b">通常一个完整的 Span 具有如下属性：</span></p>
  <ul list="ucd0f55cf">
   <li fid="u830878ab" data-lake-id="u18eff480" id="u18eff480"><span data-lake-id="ua3403cca" id="ua3403cca">Operation Name：描述了当前接口的行为语义，如具体的哪个接口，哪个URL地址。</span></li>
   <li fid="u830878ab" data-lake-id="ufd06d63b" id="ufd06d63b"><span data-lake-id="ud18848b7" id="ud18848b7">SpanId/ParentSpanId：接口调用的层级标识，用于还原 Trace 内部的层次调用关系。</span></li>
   <li fid="u830878ab" data-lake-id="ubff6f6fb" id="ubff6f6fb"><span data-lake-id="u9fd17b75" id="u9fd17b75">Start/FinishTime：接口调用的开始和结束时间，二者相减就是该次调用的耗时。</span></li>
   <li fid="u830878ab" data-lake-id="ud7b0e2ae" id="ud7b0e2ae"><span data-lake-id="u9f815a06" id="u9f815a06">StatusCode：响应状态，标识当次调用是成功或失败。</span></li>
   <li fid="u830878ab" data-lake-id="u93fcb699" id="u93fcb699"><span data-lake-id="u58b04f8c" id="u58b04f8c">Tags &amp; Events：调用附加信息</span></li>
  </ul>
  <p data-lake-id="u81b34b38" id="u81b34b38"><span data-lake-id="u0d2a72ba" id="u0d2a72ba">​</span><br></p>
  <p data-lake-id="u7393c685" id="u7393c685"><span data-lake-id="u9c6fdf96" id="u9c6fdf96">​</span><br></p>
  <p data-lake-id="u09270bb2" id="u09270bb2"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1686923722696-d0b028cd-5fbe-4952-9d40-f3ecb13ec696.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_20%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u26342098" id="u26342098"><br></p>
  <h3 data-lake-id="IvBEA" id="IvBEA"><br></h3>
  <p data-lake-id="u28124164" id="u28124164"><br></p>
  <p data-lake-id="ua8fc7246" id="ua8fc7246"><span data-lake-id="u4345f257" id="u4345f257">​</span><br></p>
 </body>
</html>